package sketch;

import sketch.generator.ChainValueGenerator;
import sketch.generator.ExhaustiveSequenceGenerator;
import sketch.generator.InorderSequenceGenerator;
import sketch.generator.RandomSequenceGenerator;
import sketch.generator.RepeatSequenceGenerator;
import sketch.generator.SequenceGenerator;
import sketch.generator.SingleSequenceGenerator;
import sketch.generator.ValueGenerator;
import sketch.skeleton.GeneratorMaps;
import sketch.util.Checker;
import sketch.util.SketchUtil;

public class MethodChoice {
	
	/**
	 * Random operator
	 * */
	//invoke any public method
	public  static SMethod[] getPublic(Class<?>[] clazz, String regex) {
		return null;
	}
	
	public  static SMethod[] getAllPublic(Class<?>[] clazz) {
		return null;
	}
	//
	public  static SMethod getAnyPublic(Class<?>[] clazz) {
		return null;
	}
	public  static SMethod getAnyPublic(Class<?>[] clazz, String[] methods) {
		return null;
	}
	
	/**
	 * Choose a method randomly for the receiver
	 * */
	
	public static SequenceGenerator<? extends Object> construct(Class<?> clazz) {
		return new SingleSequenceGenerator<SketchSequence>(null, SMethod.constructor(clazz), ValueChoice.getMockPool());
	}
	
	public static SequenceGenerator<? extends Object> randomChoose(Object receiver, SMethod smethod, ValueGenerator<? extends Object> generator) {
		return new RandomSequenceGenerator<SketchSequence>(receiver, smethod, generator);
	}
	
	public static SequenceGenerator<? extends Object> randomChoose(Object receiver, String[] methodNames, ValueGenerator<Object> generator) {
		SMethod smethod = SMethod.instance(receiver, methodNames);
		return new RandomSequenceGenerator<SketchSequence>(receiver, smethod, generator);
	}
	
	public static SequenceGenerator<? extends Object> choose(Object receiver, String method) {
		SequenceGenerator<?> generator = choose(receiver, method, /*ValueChoice.getEmptyArgumentPool()*/ ValueChoice.getMockPool());
		//start generator
		SequenceGenerator<?> retGen = GeneratorMaps.lookForGenerator(generator);
		retGen.resetReceiver(receiver);
		//end generator
		return retGen;
	}
	public static SequenceGenerator<? extends Object> choose(Object receiver, String methodName, ValueGenerator<Object[]> argGenerator) {
		if(receiver == null) {
			Checker.checkTrue(methodName.equals("<init>"), "The receiver could only be null for constructor.");
		}
		SMethod smethod = SMethod.instance(receiver, methodName);
		return new SingleSequenceGenerator<SketchSequence>(receiver, smethod, argGenerator);
	}
	
	//in order
	public static SequenceGenerator<? extends Object>[] inorder(Object receiver, String method) {
		return inorderWithArgs(receiver, method, ValueChoice.getMockPool());
	}
	public static SequenceGenerator<? extends Object> inorder(Object receiver, String methodName, ValueGenerator<? extends Object> argPool) {
		SMethod smethod = SMethod.instance(receiver, methodName);
		SequenceGenerator<? extends Object> generator = new InorderSequenceGenerator<SketchSequence>(receiver, smethod, argPool);
		//start generator
		generator = GeneratorMaps.lookForGenerator(generator);
		//end generator
		return generator;
	}
	
	public static SequenceGenerator<? extends Object>[] inorderWithArgs(Object receiver, String method, ValueGenerator<Object[]> argPool) {
		return null;
	}
	
	//the num could be randomly or non-determinstically generated
	public static SequenceGenerator<? extends Object> repeat(Object receiver, String method, int num) {
		return repeat(receiver, method, new ChainValueGenerator<Object[]>(), num);
	}
	
	public static SequenceGenerator<? extends Object> repeat(Object receiver, String methodName, ValueGenerator<Object[]> argPool, int num) {
		SMethod smethod = SMethod.instance(receiver, methodName);
		return new RepeatSequenceGenerator<SketchSequence>(receiver, smethod, argPool, num);
	}
	
	//one method but many values,  random choose up to a bound
	public static SequenceGenerator<? extends Object>[] random(Object receiver, String method, int bound) {
		return randomWithArgs(receiver, method, ValueChoice.getMockPool(), bound);
	}
	public static SequenceGenerator<? extends Object>[] random(Object receiver, String method, ValueGenerator<? extends Object> argPool, int bound) {
		return null;
	}
	private static SequenceGenerator<? extends Object>[] randomWithArgs(Object receiver, String method, ValueGenerator<Object[]> argPool, int bound) {
		return null;
	}
	
	//one method, but many values could be used as arguments,used all the values
	public static SequenceGenerator<? extends Object> permute(Object receiver, String method) {
		return permuteWithArgs(receiver, method, ValueChoice.getMockPool());
	}
	public static<T> SequenceGenerator<SketchSequence> permute(Object receiver, String methodName, ValueGenerator<T> argPool) {
		SMethod smethod = SMethod.instance(receiver, methodName);
		ExhaustiveSequenceGenerator<SketchSequence, T> permuteGenerator =
			new ExhaustiveSequenceGenerator<SketchSequence, T>(receiver, smethod, argPool);
		//test
		
		//boolean include = GeneratorMaps.containGenerator(permuteGenerator);
		//System.out.println(include + " in method choice .");
		//permuteGenerator = GeneratorMaps.lookForGenerator(permuteGenerator);
		SequenceGenerator retGen = GeneratorMaps.lookForGenerator(permuteGenerator);
		retGen.resetReceiver(receiver);
		
		//actually, we also need to reset the object pool here!
		
		if(retGen.current() != null) {
		    //retGen.evaluate();
			retGen.execute();
		}
		
		//end test
		return retGen;
	}
	private static SequenceGenerator<? extends Object> permuteWithArgs(Object receiver, String method, ValueGenerator<Object[]> argPool) {
		return null;
	}
}